/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.zhiqim.kernel.constants.HttpConstants;
import org.zhiqim.kernel.util.Bytes;

/**
 * HTTP协议中的读取头部行数据
 *
 * @version v1.5.2 @author zouzhigang 2020-4-26 新建与整理
 */
public class HttpLine implements HttpConstants
{
    //行列表和读取时的行缓冲
    private final List<String> lineList = new ArrayList<>();
    private final byte[] lineBuf = new byte[_MAX_LINE_LEN_ * 2];
    
    //行标志
    private boolean isCR;
    private boolean isLF;
    private boolean isCR2;//是否第二个回车符
    
    //单行位置&总长度
    private int pos;
    private int len;
    
    /****************************************************************************************************/
    //解析方法
    /****************************************************************************************************/
    
    /**
     * HTTP的行解析方法
     * 
     * @param input
     * @return
     * @throws IOException
     */
    public int parse(InputStream input) throws IOException
    {
        clear();
        
        int b = input.read();
        while (b != -1)
        {
            if (len > _MAX_LINE_LEN_ * _MAX_HEADER_LINE_)//头部总大小不超过128行最大值
                return _414_REQUEST_URL_TOO_LARGE_;
            
            if (pos > _MAX_LINE_LEN_)//单行总大小不超过8192
                return _414_REQUEST_URL_TOO_LARGE_;
            
            if (b == _CR_)
            {//回车
                pos = 0;//指定回首位置
                String line = Bytes.BI.getString(lineBuf, 0, (byte)0);
                if (line != null && line.trim().length() > 0)
                    lineList.add(line);
                
                Bytes.fill(lineBuf, (byte)0);
                if (isCR)
                    isCR2 = true;
                else
                    isCR = true;
            }
            else if (b== _LF_)
            {//换行
                if (isCR && isLF && isCR2)
                    break;//头部结束
                else
                    isLF = true;
            }
            else
            {
                isCR = isLF = isCR2 = false;//恢复标志
                lineBuf[pos++] = (byte)b;
                len++;
            }
            
            b = input.read();
        }
        
        //最后判断，如果出现两个CRLF，则成功，否则返回100表示未完成（用于异步读数据时）
        return (isCR && isLF && isCR2)?_0_SUCCESS_:_100_CONTINUE_;
    }
    
    /****************************************************************************************************/
    //清理&列表方法
    /****************************************************************************************************/
    
    /** 清理&重置到初始状态 */
    public void clear()
    {
        lineList.clear();
        isCR = isLF = isCR2 = false;
        pos = len = 0;
        Bytes.fill(lineBuf, (byte)0);
    }
    
    /** 获取解析之后的行列表 */
    public List<String> list()
    {
        return lineList;
    }
}
